package com.wlwx.simulator;

import com.wlwx.simulator.codec.Decoder;
import com.wlwx.simulator.codec.Encoder;
import com.wlwx.simulator.handle.CMPP20ServerHandle;
import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultEventExecutorGroup;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class CMPP20Server {

    private DefaultEventExecutorGroup defaultEventExecutorGroup;
    private final ServerBootstrap server;
    private final EventLoopGroup eventLoopGroupSelector;
    private final EventLoopGroup eventLoopGroupBoss;

    private boolean useEpoll  = false;
    private int serverWorkThreads = 32;
    private int serverBossThreads = 8;
    private int serverSelectorThreads = 8;

    public static void main(String[] args) throws InterruptedException {
        CMPP20Server server = new CMPP20Server();
        ReportThread.get();
        server.start();
    }

    public CMPP20Server() {
        server = new ServerBootstrap();

        eventLoopGroupBoss = new NioEventLoopGroup(serverBossThreads, new ThreadFactory() {
            private AtomicInteger index = new AtomicInteger(0);

            public Thread newThread(Runnable r) {
                return new Thread(r, "t-netty-boss-" + index.getAndIncrement());
            }
        });

        if(useEpoll) {
            eventLoopGroupSelector = new EpollEventLoopGroup(serverSelectorThreads, new ThreadFactory() {
                private AtomicInteger index = new AtomicInteger(0);

                public Thread newThread(Runnable r) {
                    return new Thread(r, "t-netty-selector-" + index.getAndIncrement());
                }
            });

        } else {
            eventLoopGroupSelector = new NioEventLoopGroup(serverSelectorThreads, new ThreadFactory() {
                private AtomicInteger index = new AtomicInteger(0);

                public Thread newThread(Runnable r) {
                    return new Thread(r, "t-netty-selector-" + index.getAndIncrement());
                }
            });

        }
    }

    public void start() throws InterruptedException {
        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(serverWorkThreads,
                new ThreadFactory() {
                    private AtomicInteger index = new AtomicInteger(0);

                    public Thread newThread(Runnable r) {
                        return new Thread(r, "t-netty-servercodec-" + index.getAndIncrement());
                    }
                });

        ServerBootstrap serverBootstrap = this.server.group(eventLoopGroupBoss, eventLoopGroupSelector)
                .channel(useEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .option(ChannelOption.SO_REUSEADDR, true)
                //UNIX 网络编程不建议用自带的来做心跳检测，建议自己写，cmpp协议自带心跳协议了
                .childOption(ChannelOption.SO_KEEPALIVE, false)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_SNDBUF, 65535)
                .childOption(ChannelOption.SO_RCVBUF, 65535)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(defaultEventExecutorGroup,
                                new Encoder(),
                                new Decoder(),
                                new CMPP20ServerHandle());

                    }
                });

        serverBootstrap.bind(8888).sync();

    }

}
